//========================================================= 
/**@file TEngine.h
 * @brief 
 * 
 * @date 2025-07-18   10:19:45
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_TENGINE_H_
#define _LIBZHOUYB_TENGINE_H_
//--------------------------------------------------------- 
#include "../../../include/Base.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace game {
namespace tank90 {
//--------------------------------------------------------- 
struct TVector2
{
    int x;
    int y;

    TVector2() : x(0), y(0) {}
    TVector2(int w) : x(w), y(w) {}
    TVector2(int x, int y) : x(x), y(y) {}

    bool operator ==(const TVector2& v) const
    {
        return v.x == x && v.y == y;
    }
    bool operator !=(const TVector2& v) const
    {
        return !operator==(v);
    }

    TVector2& operator /=(int v)
    {
        if (v)
        {
            x /= v;
            y /= v;
        }
        return (*this);
    }
    TVector2 operator /(int v) const
    {
        if (v)
            return TVector2(x / v, y / v);
        return TVector2();
    }
    TVector2& operator *=(int v)
    {
        x *= v;
        y *= v;
        return (*this);
    }
    TVector2 operator *(int v) const
    {
        return TVector2(x * v, y * v);
    }
    TVector2& operator +=(const TVector2& v)
    {
        x += v.x;
        y += v.y;
        return (*this);
    }
    TVector2 operator +(const TVector2& v) const
    {
        return TVector2(x + v.x, y + v.y);
    }
    TVector2& operator -=(const TVector2& v)
    {
        x -= v.x;
        y -= v.y;
        return (*this);
    }
    TVector2 operator -(const TVector2& v) const
    {
        return TVector2(x - v.x, y - v.y);
    }

    bool IsZero() const
    {
        return x == 0 && y == 0;
    }
};

#define TVector2_ZERO TVector2(0, 0)
#define TVector2_UP TVector2(0, -1)
#define TVector2_DOWN TVector2(0, 1)
#define TVector2_LEFT TVector2(-1, 0)
#define TVector2_RIGHT TVector2(1, 0)
//--------------------------------------------------------- 
struct TRect2D
{
    TVector2 position;
    TVector2 size;

    TRect2D() {}
    TRect2D(int x, int y, uint w, uint h) : position(x, y), size(w, h) {}

    /// 返回右边
    int Right() const
    {
        return position.x + size.x;
    }
    /// 返回底边
    int Bottom() const
    {
        return position.y + size.y;
    }
    /// 返回中心点
    TVector2 Center() const
    {
        return TVector2(position.x + size.x / 2, position.y + size.y / 2);
    }

    /// 返回矩形内是否包含指定的点
    bool Has(TVector2 p)
    {
        return true;
    }
    /// 返回是否和另外一个矩形的X轴相交
    bool IsOverlapX(const TRect2D& rect) const
    {
        return rect.Right() > position.x && Right() > rect.position.x;
    }
    /// 返回是否和另外一个矩形的Y轴相交
    bool IsOverlapY(const TRect2D& rect) const
    {
        return rect.Bottom() > position.y && Bottom() > rect.position.y;
    }
    /// 返回是否和矩形相交
    bool IsOverlap(const TRect2D& rect) const
    {
        return IsOverlapX(rect) && IsOverlapY(rect);
    }
};
//--------------------------------------------------------- 
struct TBody2D : public TRect2D
{
    uint layer;
    uint mask;
    uint group;
    pointer meta;

    TBody2D() : mask(0), group(0), meta(NULL) {}
    TBody2D(int x, int y, uint w, uint h) : TRect2D(x, y, w, h), mask(0), group(0), meta(NULL) {}
    virtual ~TBody2D() {}
};
//--------------------------------------------------------- 
struct TCharacter2D : public TBody2D
{
    uint speed;
    TVector2 direction;

    TCharacter2D() : speed(0) {}
    TCharacter2D(int x, int y, uint w, uint h) : TBody2D(x, y, w, h), speed(0) {}
};
//--------------------------------------------------------- 
struct TCollisionData2D
{
    /// 触发碰撞的对象
    TCharacter2D* self;
    /// 碰撞的对象
    TBody2D* body;
    /// 碰撞层
    uint layer;
    /// 碰撞方向
    TVector2 direction;

    TCollisionData2D() : self(NULL), body(NULL), layer(0) {}
};
//--------------------------------------------------------- 
class TPhysicsEngine
{
public:
    /**
     * @brief 移动物体的碰撞检测
     * @param [in] TCharacter2D & character 需要检测的对象
     * @param [in] list_t<TBody2D * > & bodies 所有待检测体
     * @param [out] list_t<TCollisionData2D> * collision_list 碰撞后的结果
     * @return bool 是否产生碰撞
     */
    bool MoveAndSlide(TCharacter2D& character, list_t<TBody2D*>& bodies, list_t<TCollisionData2D>* collision_list = NULL)
    {
        // 移动后的矩形增量
        TRect2D move;
        if (character.direction == TVector2_RIGHT)
        {
            move.position = character.position;
            move.size.x = character.size.x + character.speed;
            move.size.y = character.size.y;
        }
        else if (character.direction == TVector2_LEFT)
        {
            move.position.x = character.position.x - character.speed;
            move.position.y = character.position.y;
            move.size.x = character.size.x + character.speed;
            move.size.y = character.size.y;
        }
        else if (character.direction == TVector2_UP)
        {
            move.position.y = character.position.y - character.speed;
            move.position.x = character.position.x;
            move.size.x = character.size.x;
            move.size.y = character.size.y + character.speed;
        }
        else if (character.direction == TVector2_DOWN)
        {
            move.position = character.position;
            move.size.x = character.size.x;
            move.size.y = character.size.y + character.speed;
        }

        list_t<TBody2D*> cross_bodies;
        for (list_t<TBody2D*>::iterator itr = bodies.begin(); itr != bodies.end(); ++itr)
        {
            TBody2D& body = *(*itr);
            if ((&body != &character) && ((body.layer & character.mask) != 0x00) && move.IsOverlap(body))
            {
                cross_bodies.push_back(&body);
            }
        }
        bool is_collision = !cross_bodies.empty();
        if (is_collision)
        {
            list_t<TBody2D*> collision_bodies;
            collision_bodies.push_back(cross_bodies.front());
            cross_bodies.pop_front();
            // 检查最先碰撞的对象,对齐碰撞的边
            for (list_t<TBody2D*>::iterator itr = cross_bodies.begin(); itr != cross_bodies.end(); ++itr)
            {
                TRect2D& rect = *(*itr);
                int src = 0;
                int cmp = 0;
                TVector2 pos;
                if (character.direction == TVector2_RIGHT)
                {
                    src = (*itr)->position.x;
                    cmp = collision_bodies.front()->position.x;
                    pos.x = (*itr)->position.x - character.size.x;
                    pos.y = character.position.y;
                }
                else if (character.direction == TVector2_LEFT)
                {
                    src = -(*itr)->Right();
                    cmp = -collision_bodies.front()->Right();
                    pos.x = (*itr)->Right();
                    pos.y = character.position.y;
                }
                else if (character.direction == TVector2_UP)
                {
                    src = -(*itr)->Bottom();
                    cmp = -collision_bodies.front()->Bottom();
                    pos.x = character.position.x;
                    pos.y = (*itr)->Bottom();
                }
                else if (character.direction == TVector2_DOWN)
                {
                    src = (*itr)->position.y;
                    cmp = collision_bodies.front()->position.y;
                    pos.x = character.position.x;
                    pos.y = (*itr)->position.y - character.size.y;
                }
                if (src > cmp)
                    continue;
                if (src < cmp)
                    collision_bodies.clear();
                character.position = pos;
                collision_bodies.push_back(*itr);
            }
            if (collision_list)
            {
                for (list_t<TBody2D*>::iterator itr = collision_bodies.begin(); itr != collision_bodies.end(); ++itr)
                {
                    TCollisionData2D data;
                    data.self = &character;
                    data.body = (*itr);
                    data.layer = character.mask & (*itr)->mask;
                    collision_list->push_back(data);
                }
            }
        }
        else
        {
            character.position += character.direction * character.speed;
        }
        return is_collision;
    }
};
//--------------------------------------------------------- 
struct ITEngineObserver
{
    /// 初始化对象
    virtual void OnInit(TBody2D* body) = 0;
    /// 销毁对象
    virtual void OnFini(TBody2D* body) = 0;
    /// 每一帧触发
    virtual void OnFrame(TBody2D* body) = 0;
    /// 有更新
    virtual void OnUpdate(TBody2D* body) = 0;
    /// 检测到碰撞
    virtual void OnCollision(TBody2D* body, list_t<TCollisionData2D>& data) = 0;
    /// 每一帧最后触发(主要用于渲染)
    virtual void OnFixedFrame(list_t<TBody2D*>& bodies) = 0;
};
//--------------------------------------------------------- 
/**
 * @brief 一个简易的示例
 * @date 2025-07-23 15:09
 */
class TEngine
{
protected:
    TPhysicsEngine _physics;
    Ref<ITEngineObserver> _observer;

    list_t<TBody2D*> _bodies;
    list_t<TBody2D*> _insert_bodies;
    list_t<TBody2D*> _remove_bodies;

    void _Insert()
    {
        for (list_t<TBody2D*>::iterator itr = _insert_bodies.begin(); itr != _insert_bodies.end(); ++itr)
        {
            _observer->OnInit(*itr);
            _bodies.push_back(*itr);
        }
        _insert_bodies.clear();
    }
    void _Remove()
    {
        for (list_t<TBody2D*>::iterator rm_itr = _remove_bodies.begin(); rm_itr != _remove_bodies.end(); ++rm_itr)
        {
            for (list_t<TBody2D*>::iterator itr = _bodies.begin(); itr != _bodies.end();)
            {
                if (*rm_itr == *itr)
                {
                    _observer->OnFini(*itr);
                    itr = _bodies.erase(itr);
                    break;
                }
                ++itr;
            }
        }
        _remove_bodies.clear();
    }
public:
    void SetObserver(Ref<ITEngineObserver> ob)
    {
        _observer = ob;
    }
    /// 添加一个已实例化的对象
    void Append(TCharacter2D* body)
    {
        _insert_bodies.push_back(body);
    }
    /// 计算一帧
    void Update()
    {
        _Insert();
        list_t<TCollisionData2D> collision_list;
        for (list_t<TBody2D*>::iterator itr = _bodies.begin(); itr != _bodies.end(); ++itr)
        {
            TCharacter2D* e = ctype_cast(TCharacter2D*)(*itr);
            _observer->OnFrame(*itr);

            // 没有移动,跳过碰撞检测
            if (e->speed == 0 || e->direction.IsZero())
                continue;
            if (_physics.MoveAndSlide(*e, _bodies, &collision_list))
            {
                _observer->OnCollision(*itr, collision_list);
                collision_list.clear();
            }
            _observer->OnUpdate(*itr);
        }
        _Remove();
    }
    /// 渲染当前数据
    void Render()
    {
        _observer->OnFixedFrame(_bodies);
    }
    /// 释放对象
    void QueueFree(TBody2D* body)
    {
        // 去重
        for (list_t<TBody2D*>::iterator itr = _remove_bodies.begin(); itr != _remove_bodies.end(); ++itr)
        {
            if (*itr == body)
                return;
        }
        _remove_bodies.push_back(body);
    }
};
//--------------------------------------------------------- 
} // namespace tank90
} // namespace game
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
 #endif // #ifndef _LIBZHOUYB_TENGINE_H_
//========================================================= 